/* Copyright 2003-2009 Jetro Lauha - http://iki.fi/jetro/
 *
 * This software is provided 'as-is', without any express or implied
 * warranty.  In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software
 *    in a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 *
 * $Id: steppulse.h 59 2012-08-03 01:42:46Z trzntaat $
 * $Revision: 59 $
 *
 * Based on code from:
 * "Texturing and Modeling: A Procedural Approach", Ebert et al.
 * http://tinyurl.com/texturing-and-modeling-book
 */

#ifndef STEPPULSE_H
#define STEPPULSE_H


static float sClamp(float value, float min, float max)
{
    return value < min ? min : (value > max ? max : value);
}


static float sStep(float value, float stepPosition)
{
    return (float)(value < stepPosition ? 0 : 1);
}


static float sPulse(float value, float startPosition, float endPosition)
{
    return sStep(value, startPosition) - sStep(value, endPosition);
}


static float sBoxStep(float value, float slopeStart, float slopeEnd)
{
    float diff = slopeEnd - slopeStart;
    if (diff == 0)
        return sStep(value, slopeStart);

    return sClamp((value - slopeStart) / diff, 0, 1);
}


static float sSmoothStep(float value, float slopeStart, float slopeEnd)
{
    float diff;
    if (value < slopeStart)
        return 0;
    if (value >= slopeEnd)
        return 1;

    diff = slopeEnd - slopeStart;
    if (diff == 0)
        return sStep(value, slopeStart);

    value = (value - slopeStart) / diff;     /* normalize to [0..1] */
    return value * value * (3 - 2 * value);
}


static float sBoxPulse(float value, float upSlopeStart, float upSlopeEnd,
                       float downSlopeStart, float downSlopeEnd)
{
    return sBoxStep(value, upSlopeStart, upSlopeEnd) -
           sBoxStep(value, downSlopeStart, downSlopeEnd);
}


static float sSmoothPulse(float value, float upSlopeStart, float upSlopeEnd,
                          float downSlopeStart, float downSlopeEnd)
{
    return sSmoothStep(value, upSlopeStart, upSlopeEnd) -
           sSmoothStep(value, downSlopeStart, downSlopeEnd);
}



#ifdef STEPPULSE_SIMPLE_CONSOLE_TEST

/* To get a really simple "ascii test" in console, create a
 * test.c file with following contents and compile it:
 * #define STEPPULSE_SIMPLE_CONSOLE_TEST
 * #include "steppulse.h"
 */

#include <stdlib.h>
#include <stdio.h>

#define NUM(x) sClamp((x) * 10 + '0', '0', '9')
#define XC(x) ((x) < 0.5 ? '.' : 'x')

int main(int argc, char *argv[])
{
    int a;
    putchar('\n');
    for (a = 0; a < 50; ++a) putchar(sClamp(a - 20 + '0', '0', '9'));
    printf(" clamp\n\n");
    for (a = 0; a < 50; ++a) putchar(XC(sStep(a, 25)));
    printf(" step\n\n");
    for (a = 0; a < 50; ++a) putchar(XC(sPulse(a, 10, 40)));
    printf(" pulse\n\n");
    for (a = 0; a < 50; ++a) putchar(NUM(sBoxStep(a, 10, 40)));
    printf(" boxStep\n\n");
    for (a = 0; a < 50; ++a) putchar(NUM(sSmoothStep(a, 10, 40)));
    printf(" smoothStep\n\n");
    for (a = 0; a < 50; ++a) putchar(NUM(sBoxPulse(a, 5, 20, 30, 45)));
    printf(" boxPulse\n\n");
    for (a = 0; a < 50; ++a) putchar(NUM(sSmoothPulse(a, 5, 20, 30, 45)));
    printf(" smoothPulse\n\n");
    return EXIT_SUCCESS;
}

#endif /* STEPPULSE_SIMPLE_CONSOLE_TEST */


#endif /* !STEPPULSE_H */
